﻿using System;
using System.Collections.Generic;
using System.Text;
using SdmxMl.Common;
using SdmxMl.Structure;
using SdmxMl.Manager;

namespace SasPlugIn.SASCli
{
    public enum CodeMapSel
    {
        Code = 0,
        AnnotationTitle,
        AnnotationText
    }

    public enum TextMapSel
    {
        Name = 0,
        Description,
        AnnotationTitle,
        AnnotationText,
        AnnotationUrn
    }

    /// <summary>
    /// This class allows to retrieve code information as SAS Format instructions
    /// </summary>
    public class CodeListFormat
    {
        /// <summary>
        /// subset of languages for format generation
        /// </summary>
        private List<string> formatLanguages;
        private FormatCodeAttributes formatMap;
        

        public CodeListFormat(List<string> listLang)
        {
            formatLanguages = listLang;
            formatMap = new FormatCodeAttributes();

        }

        public CodeListFormat(List<string> listLang, FormatCodeAttributes fmt)
        {
            formatLanguages = listLang;
            formatMap = fmt;

        }

        public void FillCodelistFormat(StringBuilder sb, CodeListType clt, TextFormatType tft, string varId)
        {
            foreach (string lg in formatLanguages)
            {
                string formatId = varId + "_" + lg;
                // Ignore if no code defined
                if (clt.CodeList.Count > 0 && string.IsNullOrEmpty(lg) == false)
                {
                    // Are codes redefined ?
                    if (formatMap.CodeMap != CodeMapSel.Code)
                    {
                        CodeListType cltDup = new CodeListType();
                        foreach (ISdmxHierarchyListItem item in clt.CodeList)
                        {
                            CodeType c = new CodeType();
                            c.Id = formatMap.GetCode(item, lg);
                            cltDup.CodeList.Add(c);
                        }
                        tft = cltDup.GetDefaultTextFormat();
                    }

                    //If no format or undefined format, scan codes to check if integer
                    if (tft == null || tft.TextType == TextTypeType.Undefined)
                        tft = clt.GetDefaultTextFormat();

                    bool isInteger = (tft.TextType == TextTypeType.Integer || tft.TextType == TextTypeType.Short || tft.TextType == TextTypeType.Long);
                    // Value and codelist identification
                    sb.Append("Value ");
                    if (isInteger == false)
                        sb.Append('$');
                    sb.Append(formatId).Append(Environment.NewLine);

                    // Then in specified language a code = text
                    foreach (ISdmxHierarchyListItem item in clt.CodeList)
                    {
                        sb.Append(isInteger ? formatMap.GetCode(item, lg) : QuoteStr(formatMap.GetCode(item, lg))).Append('=');
                        string label =  formatMap.GetText(item, lg);
                        sb.Append(QuoteStr(label)).Append(Environment.NewLine);
                    }
                    sb.Append(';').Append(Environment.NewLine);
                }
            }
        }

        private string QuoteStr(string s)
        {
            return "\"" + s.Replace("\"", "'") + "\"";
        }
    }

    /// <summary>
    /// This class map code attributes to uses for format generation
    /// </summary>
    public class FormatCodeAttributes
    {
        public CodeMapSel CodeMap { get; private set; }
        public TextMapSel TextMap { get; private set; }
        public string CodeAnnotationType { get; private set; }
        public string TextAnnotationType { get; private set; }
        public bool UseAbbreviation { get; set; }

        /// <summary>
        /// Default C'tor, select standard mapping
        /// </summary>
        public FormatCodeAttributes()
        {
            CodeAnnotationType = TextAnnotationType = string.Empty;
            CodeMap = CodeMapSel.Code;
            TextMap = TextMapSel.Name;
        }
        public FormatCodeAttributes(bool useAbbrev)
        {
            CodeAnnotationType = TextAnnotationType = string.Empty;
            CodeMap = CodeMapSel.Code;
            TextMap = TextMapSel.Name;
            UseAbbreviation = useAbbrev;
        }

        /// <summary> Parametrized C'tor </summary>
        /// <param name="cdMap">elem holding code of format</param>
        /// <param name="txtMap">elem holding text of format</param>
        /// <param name="cdAnnType">annotation type used to get code</param>
        /// <param name="txtAnnType">annotation used to get text</param>
        public FormatCodeAttributes(CodeMapSel cdMap, TextMapSel txtMap, string cdAnnType, string txtAnnType)
        {
            CodeMap = cdMap;
            TextMap = txtMap;

            if (CodeMap != CodeMapSel.Code && string.IsNullOrEmpty(cdAnnType))
                throw new ArgumentException("Code annotation type required");

            if (TextMap != TextMapSel.Name && TextMap != TextMapSel.Description && string.IsNullOrEmpty(txtAnnType))
                throw new ArgumentException("Text annotation type required");

            CodeAnnotationType = cdAnnType;
            TextAnnotationType = txtAnnType;
        }


        public string GetCode(ISdmxHierarchyListItem item, string lg)
        {
            string code = item.Id;
            if (CodeMap != CodeMapSel.Code)
            {
                Annotation a = item.AnnotationList.GetAnnotationType(CodeAnnotationType);
                if (a != null)
                    code = CodeMap == CodeMapSel.AnnotationText ? a.Text.GetForLanguage(lg) : a.Title;
            }
            return code;
        }

        public string GetText(ISdmxHierarchyListItem item, string lg)
        {
            // Default
            string text = item.Name.GetForLanguage(lg);
            if (UseAbbreviation)
            {
                Annotation a = item.AnnotationList.GetAnnotationType("ABBREV");
                if (a != null)
                    text = a.Text.GetForLanguage(lg);
            }

            if (TextMap != TextMapSel.Name)
            {
                if (TextMap == TextMapSel.Description)
                    text = ((CodeType)item).Description.GetForLanguage(lg);
                else
                {
                    Annotation a = item.AnnotationList.GetAnnotationType(CodeAnnotationType);
                    if (a != null)
                    {
                        if (TextMap == TextMapSel.AnnotationUrn)
                            text = a.Url != null ? a.Url.ToString() : string.Empty;
                        else
                            text = TextMap == TextMapSel.AnnotationText ? a.Text.GetForLanguage(lg) : a.Title;
                    }
                }
            }
            return text;
        }

    }
}
